# _*_ coding: utf-8 _*_
from odoo import models, fields, api, _
from odoo.exceptions import Warning


class PurchaseRequisition(models.Model):
    _inherit = ["purchase.requisition", "stock.view.quant.mixin"]
    _name = "purchase.requisition"

    sequence = fields.Integer(string="Sequence", default=100)
    emergent = fields.Boolean(string="Emergent", default=False)
    not_emergent = fields.Boolean(string='Not Emergent', default=True)
    state = fields.Selection([('draft', 'Draft'), ('in_progress', 'Submitted'), ('confirm', 'Submitted'),
                              ('open', 'Acceptance'), ('done', 'Done'),
                              ('cancel', 'Cancelled')],
                             'Status', track_visibility='onchange', required=True,
                             copy=False, default='draft')
    name = fields.Char(string='Agreement Reference', required=True, copy=False, default=lambda self: _('New'))
    department_id = fields.Many2one('hr.department', string='User Department')
    ordering_date = fields.Date(string="Ordering Date", default=lambda self: fields.Date.today())
    attachment_ids = fields.Many2many('ir.attachment', string='附件')

    @api.onchange('user_id', 'department_id')
    def onchange_purchase_user_id(self):
        self.department_id = self.user_id \
                             and self.user_id.employee_ids \
                             and self.user_id.employee_ids[0].department_id \
                             and self.user_id.employee_ids[0].department_id.id or False

    @api.onchange('vendor_id')
    def onchange_vendor_id(self):
        if self.vendor_id:
            self.user_id = self.vendor_id.purchase_user_id and self.vendor_id.purchase_user_id.id or False
            self.onchange_purchase_user_id()
    picking_count = fields.Integer(compute='_compute_picking', string='Receptions', default=0)
    picking_ids = fields.Many2many('stock.picking', compute='_compute_picking', string='Receptions', copy=False)

    @api.multi
    def toggle_emergent(self):
        for record in self:
            record.emergent = not record.emergent
            record.not_emergent = not record.emergent
            if record.emergent:
                record.sequence = 1
            else:
                record.sequence = 100

    @api.multi
    def action_view_quants(self):
        self.ensure_one()
        products = self.line_ids.mapped("product_id")
        return self.action_view_quant_by_product_ids(products.ids)

    def action_confirm_all_draft_lines(self):
        for req in self:
            draft_lines = req.line_ids
            if draft_lines:
                draft_lines.action_confirm()

    def action_cancel_all_draft_lines(self):
        for req in self:
            draft_lines = req.line_ids
            if draft_lines:
                draft_lines.action_cancel()

    purchase_request_line_ids = fields.One2many("purchase.request.order.line",
                                                compute="_compute_purchase_request_line_ids")

    purchase_request_line_count = fields.Integer(compute="_compute_purchase_request_line_ids")

    purchase_request_order_ids = fields.One2many("purchase.request.order",
                                                 compute="_compute_purchase_request_order_ids")
    purchase_request_order_count = fields.Integer(compute="_compute_purchase_request_order_ids")

    def _compute_purchase_request_line_ids(self):
        for req in self:
            req.purchase_request_line_ids = self.env["purchase.request.order.line"].search([
                ("requisition_line_id", "in", req.line_ids.ids),
                ("state", "=", "price_comparing")
            ])
            req.purchase_request_line_count = len(req.purchase_request_line_ids)

    def _compute_purchase_request_order_ids(self):
        for req in self:
            lines = self.env["purchase.request.order.line"].search([
                ("requisition_line_id", "in", req.line_ids.ids),
                ("state", "=", "price_comparing")
            ])
            req.purchase_request_order_ids = lines.mapped("order_id")
            req.purchase_request_order_count = len(req.purchase_request_order_ids)

    @api.multi
    def action_view_purchase_request_lines(self):
        self.ensure_one()
        action = self.env.ref("purchase_order_extend.purchase_request_order_line_action_compare_price")
        if not action:
            return True

        action_dict = action.read()[0]

        domain = [
            ("id", "in", self.purchase_request_line_ids.ids),
            ("state", "=", "price_comparing")
        ]
        action_dict["domain"] = domain
        if not self.purchase_request_line_ids:
            action_dict["context"] = None
        return action_dict

    @api.multi
    def action_view_purchase_request_orders(self):
        self.ensure_one()
        action = self.env.ref("purchase_order_extend.purchase_request_order_action_compare_price")
        if not action:
            return True

        action_dict = action.read()[0]

        domain = [
            ("id", "in", self.purchase_request_order_ids.ids),
            ("state", "=", "price_comparing")
        ]
        action_dict["domain"] = domain
        return action_dict

    @api.multi
    def action_cancel(self):
        # try to set all associated quotations to cancel state
        for requisition in self:
            pr_ids = self.env["purchase.request.order.line"].search([
                ("requisition_line_id", "in", requisition.line_ids.ids)])
            pr_total_count = len(pr_ids)
            pr_close_count = len(pr_ids.filtered(lambda line: line.state == 'cancel'))
            po_ids = self.env["purchase.order"].search([
                ("id", "in", pr_ids.mapped('order_id.po_id').ids)])
            po_total_count = len(po_ids)
            po_close_count = len(po_ids.filtered(lambda line: line.state == 'cancel'))
            if po_total_count > po_close_count:
                raise Warning(_("Found non-canceled purchase order, need cancel these purchase order first!"))
            if pr_total_count > pr_close_count:
                raise Warning(_("Found non-canceled purchase request order, need cancel these purchase request order first!"))
            requisition.line_ids.write({'state': 'cancel'})
        self.write({'state': 'cancel'})

    @api.multi
    def action_draft(self):
        self.line_ids.write({'state': 'draft'})
        self.write({'state': 'draft'})

    @api.model
    def create(self, vals):
        if vals.get('name', _('New')) == _('New'):
            if 'company_id' in vals:
                vals['name'] = self.env['ir.sequence'].with_context(force_company=vals['company_id']).next_by_code('purchase.order.requisition') or _('New')
            else:
                vals['name'] = self.env['ir.sequence'].next_by_code('purchase.order.requisition') or _('New')
        return super(PurchaseRequisition, self).create(vals)

    @api.multi
    def action_confirm(self):
        if self.check_maximum_purchase_limit_qty():
            raise Warning(_("Product qty will out of the purchase limit qty, process can't going on."))
        self.write({'state': 'confirm'})

    @api.multi
    def action_in_progress(self):
        if self.check_maximum_purchase_limit_qty():
            raise Warning(_("Product qty will out of the purchase limit qty, process can't going on."))
        if not all(obj.line_ids for obj in self):
            raise Warning(_('You cannot confirm call because there is no product line.'))
        if self.schedule_date < self.ordering_date:
            raise Warning(u'需求日期不可小于建单日期')
        self.write({'state': 'in_progress'})

    @api.multi
    def action_open(self):
        if len(self.line_ids.filtered(lambda l: l.state == 'draft').ids) > 0:
            raise Warning(u'无法验证请购单,请检查请购明细状态')
        # for line in self.line_ids:
        #     product_lines = self.env['purchase.requisition.line'].search([('product_id', '=', line.product_id.id)])
        #     for product_line in product_lines:
        #         product_line.write({'last_create_date': product_line.current_create_date, 'last_product_qty': product_line.current_product_qty})
        #         # product_line.last_create_date = product_line.current_create_date
        #         # product_line.last_product_qty = product_line.current_product_qty
        #         product_line.write({'current_create_date': fields.Date.today(), 'current_product_qty': line.product_qty})
        #         # product_line.current_create_date = fields.Date.today()
        #         # product_line.current_product_qty = line.product_qty
        return super(PurchaseRequisition, self).action_open()

    @api.model
    def check_maximum_purchase_limit_qty(self):
        self.ensure_one()
        product_required = {}
        # sum all line's qty
        for line in self.line_ids:
            if line.product_id in product_required:
                product_required[line.product_id.id] += line.product_qty
            else:
                product_required[line.product_id.id] = line.product_qty
        # check product_qty + safety stock qty must lt than purchase limit qty
        product = self.env['product.product']
        for product_id, product_qty in product_required.iteritems():
            pp = product.browse(product_id)
            if pp.product_purchase_limit_control and pp.virtual_available - pp.safety_stock_qty + product_qty > pp.product_purchase_limit:
                return True
        return False

    @api.multi
    def action_view_picking(self):
        '''
        This function returns an action that display existing picking orders of given purchase order ids.
        When only one found, show the picking immediately.
        '''
        action = self.env.ref('stock.action_picking_tree')
        result = action.read()[0]

        # override the context to get rid of the default filtering on picking type
        result['context'] = {}
        pick_ids = sum([order.picking_ids.ids for order in self], [])
        # choose the view_mode accordingly
        if len(pick_ids) > 1:
            result['domain'] = "[('id','in',[" + ','.join(map(str, pick_ids)) + "])]"
        elif len(pick_ids) == 1:
            res = self.env.ref('stock.view_picking_form', False)
            result['views'] = [(res and res.id or False, 'form')]
            result['res_id'] = pick_ids and pick_ids[0] or False
        return result

    def _compute_picking(self):
        for req in self:
            lines = self.env["purchase.request.order.line"].search([
                ("requisition_line_id", "in", req.line_ids.ids)
            ])
            purchase_request_order_ids = lines.mapped("order_id")
            po_ids = self.env['purchase.order'].search([('pr_id', 'in', purchase_request_order_ids.ids)])
            for order in po_ids:
                pickings = self.env['stock.picking']
                for line in order.order_line:
                    # We keep a limited scope on purpose. Ideally, we should also use move_orig_ids and
                    # do some recursive search, but that could be prohibitive if not done correctly.
                    moves = line.move_ids | line.move_ids.mapped('returned_move_ids')
                    moves = moves.filtered(lambda r: r.state != 'cancel')
                    pickings |= moves.mapped('picking_id')
                req.picking_ids += pickings
                req.picking_count += len(pickings)


